package Graphic;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.LinkedList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class GT implements Runnable, ActionListener {
	JFrame mainFrame;
	JPanel mainPanel;
	GridBagLayout gridbag;
	GridBagConstraints c;
	// -------------- Menu Items -------------------
	JMenuItem open;
	JMenuItem exit;
	JMenuItem credits;
	// -------------- Settings Items ---------------
	JTextArea instrArea;
	ButtonGroup cacheType;
	JTextField blockNum;
	JTextField blockSize;
	JTextField procNum;
	JTextField memSize;
	ButtonGroup protocolType;
	JTextField cc, cm, bu, fl;
	// -------------- Simulate ---------------------
	JTextField currentOpField;
	JButton simButton;
	// -------------- Memory -----------------------
	JTextArea memoryField;
	// -------------- Processors -------------------
	JScrollPane scrollProcP;
	JPanel stateP;

	// ---------------------------------------------
	private JMenuBar createMenu() {
		// Create the menu bar
		JMenuBar menuBar = new JMenuBar();

		// Create a menu
		JMenu file = new JMenu("File");
		menuBar.add(file);

		// Create menu items
		open = new JMenuItem("Open");
		open.addActionListener(this);
		file.add(open);

		file.addSeparator();

		exit = new JMenuItem("Exit");
		exit.addActionListener(this);
		file.add(exit);

		// Create a menu
		JMenu about = new JMenu("About");
		menuBar.add(about);

		// Create a menu item
		credits = new JMenuItem("Credits");
		credits.addActionListener(this);
		about.add(credits);

		return menuBar;
	}

	private JPanel cacheType() {
		JPanel cacheP = new JPanel(new GridLayout(1, 2));
		cacheP.setBorder(BorderFactory.createTitledBorder("Cache Type"));
		cacheType = new ButtonGroup();
		JRadioButton option;
		option = new JRadioButton("Direct Access");
		option.setSelected(true);
		cacheType.add(option);
		cacheP.add(option);
		option = new JRadioButton("Associative");
		cacheType.add(option);
		cacheP.add(option);
		return cacheP;
	}

	private JPanel cacheSize() {
		JPanel cacheP = new JPanel(new GridLayout(2, 2));
		cacheP.setBorder(BorderFactory.createTitledBorder("Cache Dimension"));
		cacheP.add(new JLabel("Block Number:"));
		blockNum = new JTextField("4");
		cacheP.add(blockNum);
		cacheP.add(new JLabel("Block Size (Byte):"));
		blockSize = new JTextField("2");
		cacheP.add(blockSize);
		return cacheP;
	}

	private JPanel memAndProc() {
		JPanel cacheP = new JPanel(new GridLayout(2, 2));
		cacheP.setBorder(BorderFactory.createTitledBorder(""));
		cacheP.add(new JLabel("Processors Number:"));
		procNum = new JTextField("4");
		cacheP.add(procNum);
		cacheP.add(new JLabel("Memory Size (Byte):"));
		memSize = new JTextField("64");
		cacheP.add(memSize);
		return cacheP;
	}

	private JPanel protocolType() {
		JPanel cacheP = new JPanel(new GridLayout(1, 2));
		cacheP.setBorder(BorderFactory.createTitledBorder("Protocol Type"));
		protocolType = new ButtonGroup();
		JRadioButton option;
		option = new JRadioButton("MSI");
		option.setSelected(true);
		protocolType.add(option);
		cacheP.add(option);
		option = new JRadioButton("MESI");
		protocolType.add(option);
		cacheP.add(option);
		return cacheP;
	}

	private JPanel cycles() {
		JPanel cyclesP = new JPanel(new GridLayout(4, 2));
		cyclesP.setBorder(BorderFactory.createTitledBorder("Cycles"));
		cyclesP.add(new JLabel("C-C (Cycles):"));
		cc = new JTextField("70");
		cyclesP.add(cc);
		cyclesP.add(new JLabel("C-M (Cycles):"));
		cm = new JTextField("80");
		cyclesP.add(cm);
		cyclesP.add(new JLabel("BusUpgr (Cycles):"));
		bu = new JTextField("60");
		cyclesP.add(bu);
		cyclesP.add(new JLabel("Flush (Cycles):"));
		fl = new JTextField("50");
		cyclesP.add(fl);
		return cyclesP;
	}

	private JPanel instructions() {
		JPanel instructionsP = new JPanel(new GridLayout(1, 2));
		instructionsP.setBorder(BorderFactory
				.createTitledBorder("Instructions List"));

		instrArea = new JTextArea(15, 20);
		instrArea.setEditable(false);
		instrArea.setFont(new Font("SansSerif", Font.PLAIN, 14));
		instrArea
				.setText("To start select a file\nfrom top-left side File Menu.");

		JScrollPane scrollText = new JScrollPane(instrArea);
		scrollText
				.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		instructionsP.add(scrollText);
		return instructionsP;
	}

	private JPanel button() {
		JPanel buttonP = new JPanel(new GridLayout(1, 2));
		buttonP.setBorder(BorderFactory.createTitledBorder(""));
		simButton = new JButton("Simulate");
		simButton.addActionListener(this);
		//simButton.setEnabled(false);
		buttonP.add(simButton);
		return buttonP;
	}

	private void settingsPanel(final int gridx, final int gridy) {
		JPanel settingsP = new JPanel();
		settingsP.setLayout(new BoxLayout(settingsP, BoxLayout.Y_AXIS));
		settingsP.setPreferredSize(new Dimension(300, 400));
		settingsP.setBorder(BorderFactory.createTitledBorder("Settings"));

		settingsP.add(memAndProc());
		settingsP.add(cacheType());
		settingsP.add(cacheSize());
		settingsP.add(protocolType());
		settingsP.add(instructions());
		settingsP.add(cycles());
		settingsP.add(button());

		c.gridx = gridx;
		c.gridy = gridy;
		gridbag.setConstraints(settingsP, c);

		mainPanel.add(settingsP);
	}

	private void memoryPanel(final int gridx, final int gridy) {
		JPanel memoryP = new JPanel();
		memoryP.setLayout(new BoxLayout(memoryP, BoxLayout.Y_AXIS));
		memoryP.setPreferredSize(new Dimension(300, 400));
		memoryP.setBorder(BorderFactory.createTitledBorder("Memory"));

		memoryField = new JTextArea(10, 20);
		memoryField.setEditable(false);
		memoryField
				.setText("In memoria ho una banana\nIn memoria ho due banane");
		memoryField.setFont(new Font("SansSerif", Font.PLAIN, 14));

		JScrollPane scrollText = new JScrollPane(memoryField);
		scrollText
				.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

		memoryP.add(scrollText);
		c.gridx = gridx;
		c.gridy = gridy;
		gridbag.setConstraints(memoryP, c);
		mainPanel.add(memoryP);
	}

	private JPanel processorP(final int procId, final int blockNum) {
		JPanel procP = new JPanel(new GridLayout(blockNum + 1, 4));
		procP.setBorder(BorderFactory.createTitledBorder("P" + procId));
		List<JTextField> cellList = new LinkedList<JTextField>();
		System.out.println(blockNum);
		
		procP.add(new JLabel(" Block"));
		procP.add(new JLabel("   State"));
		procP.add(new JLabel("   Tag"));
		procP.add(new JLabel("   Data"));
		for (int r = 0; r < blockNum; r++) {
			procP.add(new JLabel("  B" + r));
			JTextField tf1 = new JTextField("I");
			tf1.setEditable(false);
			// tf1.setFont(new Font(, Font., 12));
			cellList.add(tf1);
			procP.add(tf1);
			JTextField tf2 = new JTextField("0000");
			tf2.setEditable(false);
			cellList.add(tf2);
			procP.add(tf2);
			JTextField tf3 = new JTextField("0000");
			tf3.setEditable(false);
			cellList.add(tf3);
			procP.add(tf3);
		}
		return procP;
	}

	/**
	 * @param gridx
	 * @param gridy
	 * @param blockNum
	 * @param procNum
	 */
	private void statePanel(final int gridx, final int gridy,
			final int blockNum, final int procNum) {

		stateP = new JPanel();
		stateP.setPreferredSize(new Dimension(640, 640));
		stateP.setBorder(BorderFactory.createTitledBorder("Cache States"));
		scrollProcP = new JScrollPane(stateP);

		c.gridx = gridx;
		c.gridy = gridy;
		gridbag.setConstraints(scrollProcP, c);
		mainPanel.add(scrollProcP);
	}

	private void setProcessors(final int blockNum, final int procNum) {
		stateP.removeAll();
		for (int i = 0; i < procNum; i++)
			stateP.add(processorP(i, blockNum));
	}

	private void currentOperationPanel(final int gridx, final int gridy) {
		JPanel currentP = new JPanel();
		currentP.setBorder(BorderFactory
				.createTitledBorder("Current Operation"));

		currentOpField = new JTextField("", 30);
		currentOpField.setEditable(false);
		currentOpField.setText("Muovi dal P0 al P1 il dato 120");
		currentOpField.setFont(new Font("SansSerif", Font.PLAIN, 14));

		currentP.add(currentOpField);
		c.gridx = gridx;
		c.gridy = gridy;
		gridbag.setConstraints(currentP, c);
		mainPanel.add(currentP);
	}

	public void run() {
		mainFrame = new JFrame(
				"J-MAS : Java Multiprocessor Architectur Simulator");
		mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		mainFrame.setJMenuBar(createMenu());
		gridbag = new GridBagLayout();
		c = new GridBagConstraints();

		mainPanel = new JPanel();
		mainPanel.setLayout(gridbag);

		c.fill = GridBagConstraints.BOTH;

		c.gridheight = GridBagConstraints.VERTICAL;
		settingsPanel(0, 0);

		c.gridheight = 1;
		statePanel(1, 0, 4, 4);

		c.gridheight = GridBagConstraints.VERTICAL;
		memoryPanel(2, 0);

		c.gridheight = 1;
		currentOperationPanel(1, 1);

		mainPanel.setSize(300, 100);

		mainFrame.add(mainPanel);
		mainFrame.pack();
		mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
		mainFrame.setVisible(true);
	}

	public void actionPerformed(ActionEvent e) {
		Object event = e.getSource();
		if (event == open) {
			// Create a file chooser
			final JFileChooser fc = new JFileChooser();
			// In response to a button click:
			int returnVal = fc.showOpenDialog(mainFrame);
			fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
			if (returnVal == JFileChooser.APPROVE_OPTION) {
				try {
					instrArea.setText("");
					BufferedReader buff = new BufferedReader(new FileReader(fc
							.getSelectedFile().getAbsolutePath()));
					String line = "";
					while ((line = buff.readLine()) != null) {
						instrArea.append(line + "\n");
					}
					buff.close();
					simButton.setEnabled(true);
				} catch (Exception ex) {
					JOptionPane.showMessageDialog(mainFrame, "File Error!",
							"The file is invalid.", JOptionPane.ERROR_MESSAGE);
				}

			}
		}
		if (event == credits) {
			JOptionPane.showMessageDialog(mainFrame,
					"SCIUTO Lorenzo - sciuto.lorenzo@gmail.com\n"
							+ "URZI' Erik - erik.urzi@gmail.com\n"
							+ "COPPOLA Giuseppe - pinuztribe@gmail.com",

					"J-MAS: Authors", JOptionPane.INFORMATION_MESSAGE);
		}
		if (event == exit) {
			int answer = JOptionPane.showConfirmDialog(mainFrame,
					"Do you really want to close?", "Close",
					JOptionPane.YES_NO_OPTION);
			if (answer == JOptionPane.YES_OPTION)
				System.exit(0);
		}
		if (event == simButton) {
			int answer = JOptionPane.showConfirmDialog(mainFrame,
					"Start Simulation?", "Simulation",
					JOptionPane.YES_NO_OPTION);
			if (answer == JOptionPane.YES_OPTION){
				memoryField.setText("Simulation in progress");
				try{
					setProcessors(Integer.parseInt(blockNum.getText()),Integer.parseInt(procNum.getText()));	
				}catch(Exception ex){
					JOptionPane.showMessageDialog(mainFrame,
							"Invalid Options.\nCheck and Correct mistakes from settings panel",
							"ERROR", JOptionPane.ERROR_MESSAGE);
				}
				mainFrame.repaint();
				mainFrame.setVisible(true);
			}
		}
	}

	public static void main(String args[]) {
		new Thread(new GT()).start();
	}
}